<?php

namespace app\admin\model\facrm;

use addons\facrm\library\Alter;
use app\common\model\Config;
use think\Db;
use think\Exception;
use think\exception\PDOException;
use think\Model;

class Fields extends Model
{

    // 表名
    protected $name = 'facrm_fields';
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';
    // 定义时间戳字段名
    protected $createTime = 'createtime';
    protected $updateTime = 'updatetime';
    // 追加属性
    protected $append = [
        'status_text',
        'content_list',
    ];
    protected $type = [
        'setting' => 'json',
    ];
    protected static $listField = ['select', 'selects', 'checkbox', 'radio', 'array'];

    public function setError($error)
    {
        $this->error = $error;
    }

    protected static function init()
    {
        $beforeUpdateCallback = function ($row) {
            if (!preg_match("/^([a-zA-Z0-9_]+)$/i", $row['name'])) {
                throw new Exception("字段只支持字母数字下划线");
            }
            if (is_numeric(substr($row['name'], 0, 1))) {
                throw new Exception("字段不能以数字开始");
            }

            if (isset($row['oldname']) && $row['oldname'] != $row['name']) {
                $table = "facrm_" . $row['source'];
                $tableFields = \think\Db::name($table)->getTableFields();
                if (in_array(strtolower($row['name']), $tableFields)) {
                    throw new Exception("字段已经存在了");
                }
            }

        };
        $beforeInsertCallback = function ($row) {
            if (!preg_match("/^([a-zA-Z0-9_]+)$/i", $row['name'])) {
                throw new Exception("字段只支持字母数字下划线");
            }
            if (is_numeric(substr($row['name'], 0, 1))) {
                throw new Exception("字段不能以数字开始");
            }
            $table = "facrm_" . $row['source'];
            $tableFields = \think\Db::name($table)->getTableFields();

            if (in_array(strtolower($row['name']), $tableFields)) {
                throw new Exception("字段已经存在了");
            }
        };


        $afterInsertCallback = function ($row) {
            //为了避免引起更新的事件回调，这里采用直接执行SQL的写法
            Db::name('facrm_fields')->update(['id' => $row['id'], 'weigh' => $row['id']]);
            Fields::refreshTable($row, 'insert');
        };
        $afterUpdateCallback = function ($row) {
            Fields::refreshTable($row, 'update');
        };

        self::beforeInsert($beforeInsertCallback);
        self::beforeUpdate($beforeUpdateCallback);

        self::afterInsert($afterInsertCallback);
        self::afterUpdate($afterUpdateCallback);

        self::afterDelete(function ($row) {
            Fields::refreshTable($row, 'delete');
        });
    }

    public function getContentListAttr($value, $data)
    {
        
        return in_array($data['type'], self::$listField) ? Config::decode($data['content']) : $data['content'];
    }

    public static function refreshTable($row, $action = 'insert')
    {
        $model = null;
        $table = "facrm_" . $row['source'];

        $alter = Alter::instance();
        if (isset($row['oldname']) && $row['oldname'] != $row['name']) {
            $alter->setOldname($row['oldname']);
        }
        $alter
            ->setTable($table)
            ->setName($row['name'])
            ->setLength($row['length'])
            ->setContent($row['content'])
            ->setDecimals($row['decimals'])
            ->setDefaultvalue($row['defaultvalue'])
            ->setComment($row['title'])
            ->setType($row['type']);
        if ($action == 'insert') {
            $sql = $alter->getAddSql();
        } elseif ($action == 'update') {
            $sql = $alter->getModifySql();
        } elseif ($action == 'delete') {
            $sql = $alter->getDropSql();
        } else {
            throw new Exception("操作类型错误");
        }
        try {
            db()->execute($sql);
        } catch (PDOException $e) {
            throw new Exception($e->getMessage());
        }
    }


    public function getStatusList()
    {
        return ['normal' => __('Normal'), 'hidden' => __('Hidden')];
    }

    public function getStatusTextAttr($value, $data)
    {
        $value = $value ? $value : $data['status'];
        $list = $this->getStatusList();
        return isset($list[$value]) ? $list[$value] : '';
    }


    /**
     * 获取指定类型的自定义字段列表
     */
    public static function getCustomFields($source, $values = [], $conditions = [])
    {
        $fields = Fields::where('source', $source)
            ->where($conditions)
            ->where('status', 'normal')
            ->order('weigh desc,id desc')
            ->select();
        foreach ($fields as $k => $v) {
            //优先取编辑的值,再次取默认值
            $v->value = isset($values[$v['name']]) ? $values[$v['name']] : (is_null($v['defaultvalue']) ? '' : $v['defaultvalue']);
            $v->rule = str_replace(',', '; ', $v->rule);
            if (in_array($v['type'], ['checkbox', 'lists', 'images'])) {
                $checked = '';
                if ($v['minimum'] && $v['maximum']) {
                    $checked = "{$v['minimum']}~{$v['maximum']}";
                } elseif ($v['minimum']) {
                    $checked = "{$v['minimum']}~";
                } elseif ($v['maximum']) {
                    $checked = "~{$v['maximum']}";
                }
                if ($checked) {
                    $v->rule .= (';checked(' . $checked . ')');
                }
            }
            if (in_array($v['type'], ['checkbox', 'radio']) && stripos($v->rule, 'required') !== false) {
                $v->rule = str_replace('required', 'checked', $v->rule);
            }
            if (in_array($v['type'], ['selects'])) {
                $v->extend .= (' ' . 'data-max-options="' . $v['maximum'] . '"');
            }
        }

        return $fields;
    }

    /**
     * 获取自定义字段【在table上用的】
     * @param $source
     * @param array $values
     * @param array $conditions
     * @return array
     */
    public static function getCustomFieldsTable($source, $values = [], $conditions = [])
    {
        $temp = array();
        $fields = self::getCustomFields($source, $values, $conditions);

        if ($fields) {
            foreach ($fields as $key => $row) {

                $temp[$key]['field'] = $row['name'];
                $temp[$key]['title'] = $row['title'];
                $temp[$key]['operate'] = $row['isfilter'] ? 'LIKE' : false;
                $temp[$key]['search'] = $row['isfilter'] ? true : false;
                $temp[$key]['visible'] = $row['islist'] ? true : false;

                switch ($row['type']) {
                    case 'radio':
                    case 'select':
                        $temp[$key]['operate'] = $row['isfilter'] ? '=' : false;
                        $temp[$key]['searchList'] = $row['content_list'];
                        $temp[$key]["formatter"] = 'Table.api.formatter.status';
                        break;
                    case 'checkbox':
                    case 'selects':

                        $temp[$key]['searchList'] = $row['content_list'];
                        $temp[$key]["formatter"] = 'Table.api.formatter.flag';
                        $temp[$key]['operate'] = $row['isfilter'] ? 'find_in_set' : false;
                        break;
                    case 'datetime':
                        $temp[$key]["formatter"] = 'Table.api.formatter.datetime';
                        $temp[$key]['operate'] = $row['isfilter'] ? 'RANGE' : false;
                        $temp[$key]['addclass'] = 'datetimerange';
                        break;
                    case 'image':
                    case 'images':
                        $temp[$key]["formatter"] = 'Table.api.formatter.images';
                        $temp[$key]["events"] = 'Table.api.events.image';
                        break;
                    case 'file':
                    case 'files':
                        $temp[$key]["formatter"] = 'Controller.api.formatter.thumb';
                        break;
                    case 'switch':
                        $temp[$key]["formatter"] = 'Table.api.formatter.toggle';
                        break;
                    case 'selectpages':
                    case 'selectpage':
                        /**
                         * $js = <<<eof
                         * gree=function (value, row, index) {
                         * var that=$(this);
                         * $.ajax({
                         * type: "POST",
                         * url: "facrm/fields/selectpage?admin=1&id={$row->id}",
                         * data: {keyValue: value, 'searchKey': value},
                         * dataType: "json",
                         * success: function(data){
                         * console.log(index);
                         * table.bootstrapTable('updateRow', {
                         * index: index,
                         * row: {
                         * mobile: 1,
                         * }
                         * });
                         * }
                         * });
                         * }
                         * eof;**/
                        $temp[$key]["extend"] = "data-source='facrm/fields/selectpage?admin=1&id={$row->id}'
                        data-primary-key='{$row->setting['primarykey']}' data-field='{$row->setting['field']}' ";
                        $temp[$key]['addclass'] = 'selectpage';
                        $temp[$key]['operate'] = '=';
                        $temp[$key]['visible'] = false;//不让在列表显示，未解决性能问题
                        break;
                    default:


                }

            }
        }

        return $temp;
    }

    public function getExtendHtmlAttr($value, $data)
    {
        $result = preg_replace_callback("/\{([a-zA-Z]+)\}/", function ($matches) use ($data) {
            if (isset($data[$matches[1]])) {
                return $data[$matches[1]];
            }
        }, $data['extend']);
        return $result;
    }

    /**
     * 表单验证
     * @param $source
     * @param $param
     * @param string $type 验证类型 system系统字段，其它自定义字段
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function validateByForm($source, &$param,$type='')
    {

        if ($type=='system'){
            $values =(new \app\admin\model\facrm\Setting())->where('key', 'validate_tpl_'.$source)->value('values');
            $fields=$values?json_decode($values,true):[];
        }else{
            $fields = self::where('source', $source)->where('status','normal')->order('weigh desc,id desc')->select();
        }
        $rules = [];
        $msg = [];
        foreach ($fields as $item) {
            $rule = explode(',', $item['rule']);
            foreach ($rule as $res) {
                //处理null问题
                if (isset($param[$item['name']])&&!is_array($param[$item['name']])&&trim($param[$item['name']])=='null'){
                    $param[$item['name']]=NULL;
                }

                if (isset($param[$item['name']])&&$param[$item['name']]==''&&isset($item['type'])&&in_array($item['type'],
                        ['time','datetime','date'])){
                    $param[$item['name']]=NULL;
                }
                //解决时间日期、select为空报错问题
                if (isset($param[$item['name']])&&$param[$item['name']]==''&&isset($item['type'])&&in_array($item['type'],
                        ['select','selects','radio','radio']))
                    unset($param[$item['name']]);


                switch ($res) {
                    case 'required':
                        $rules["{$item['name']}"][] = 'require';
                        $msg["{$item['name']}.require"] = $item['title'] . '不能为空！';
                        break;
                    case 'digits':
                        $rules["{$item['name']}"][] = 'number';
                        $msg["{$item['name']}.number"] = $item['title'] . '必须是数字！';
                        break;
                    case 'letters':
                        $rules["{$item['name']}"][] = 'alpha';
                        $msg["{$item['name']}.alpha"] = $item['title'] . '必须是字母！';
                        break;
                    case 'date':
                        $rules[$item['name']][] = 'date';
                        $msg["{$item['name']}.date"] = $item['title'] . '格式错误！';
                        break;
                    case 'time':
                        $rules["{$item['name']}"][] = 'regex:/^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$/';
                        $msg["{$item['name']}"] = $item['title'] . '格式错误！';
                        break;
                    case 'email':
                        $rules[$item['name']][] = 'email';
                        $msg["{$item['name']}.email"] = $item['title'] . '格式错误！';
                        break;
                    case 'url':
                        $rules[$item['name']] = 'url';
                        $msg["{$item['name']}.url"] = $item['title'] . '格式错误！';
                        break;
                    case 'qq':
                        $rules["{$item['name']}"][] = 'regex:/^[1-9][0-9]{4,10}$/';
                        $msg["{$item['name']}"] = $item['title'] . '格式错误！';
                        break;
                    case 'IDcard':
                        $rules["{$item['name']}"][] = 'regex:/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/';
                        $msg["{$item['name']}"] = $item['title'] . '格式错误！';
                        break;
                    case 'tel':
                        $rules["{$item['name']}"][] = 'regex:/^\d{3}-\d{8}$|^\d{4}-\d{7,8}$/';
                        $msg["{$item['name']}"] = $item['title'] . '格式错误！';
                        break;
                    case 'mobile':
                        $rules["{$item['name']}"][] = 'regex:/^1\d{10}$/';
                        $msg["{$item['name']}"] = $item['title'] . '格式错误！';
                        break;
                    case 'zipcode':
                        $rules["{$item['name']}"][] = 'regex:/^(0[1-7]|1[0-356]|2[0-7]|3[0-6]|4[0-7]|5[1-7]|6[1-7]|7[0-5]|8[013-6])\d{4}$/';
                        $msg["{$item['name']}"] = $item['title'] . '格式错误！';
                        break;
                    case 'chinese':
                        $rules[$item['name']][] = 'chs';
                        $msg["{$item['name']}.chs"] = $item['title'] . '只能填写中文！';
                        break;
                    case 'username':
                        $rules["{$item['name']}"][] = 'regex:/^[a-zA-Z0-9_]{3,12}$/';
                        $msg["{$item['name']}"] = $item['title'] . '请填写3-12位数字、字母、下划线！';
                        break;
                    case 'password':
                        $rules["{$item['name']}"][] = 'regex:/^[0-9a-zA-Z!@#$%^&*?]{6,16}$/';
                        $msg["{$item['name']}"] = $item['title'] . '请填写6-16位字符，不能包含空格！';
                        break;

                }
            }



        }
        $validate = new \think\Validate($rules, $msg);
        $return['status'] = $validate->check($param);
        $return['msg'] = $return['status'] ? '' : $validate->getError();
        return $return;
    }


    /**
     * 自定义排序
     */
    public static function diyorder($admin_id, $type = "customer")
    {
        $cache_key=("diy".$type."_".$admin_id);


        if (!extension_loaded('redis')) {
            $order=\app\admin\model\facrm\Setting::where('key',$cache_key)->value("values");
            $order=$order?json_decode($order):[];
        } else {
            $queue_config=\think\Config::get('queue');
            $redis_cache = \think\Cache::connect([
                'type' => 'redis',
                'password'=>isset($queue_config['password'])?$queue_config['password']:'',
                'host'=>isset($queue_config['host'])?$queue_config['host']:'127.0.0.1',
                'port'=>isset($queue_config['port'])?$queue_config['port']:'6379'
            ]);
            $order = $redis_cache->get($cache_key);
        }

        $fields = \app\admin\model\facrm\Fields::getCustomFieldsTable($type, [], 'isfilter=1 or islist=1');
        $config_file = ADDON_PATH . "facrm" . DS . 'config' . DS . "{$type}field.php";
        $default_fields = array();
        if (is_file($config_file)) {
            $default_fields = include $config_file;
        }
        $fields = array_merge($default_fields, $fields);

        //自定义排序
        if ($order) {
            $order = array_merge($order, array_column($fields, 'field'));

            usort($fields, function ($a, $b) use ($order) {
                $pos_a = array_search($a['field'], $order);
                $pos_b = array_search($b['field'], $order);
                return $pos_a - $pos_b;
            });
        }
        return $fields;

    }

    /**
     * 缓存排序【要永久缓存】
     * @param $admin_id
     * @param $params
     * @param string $type
     * @return bool
     */
    public static function saveDiyorder($admin_id, $params, $type = "customer")
    {
        $cache_key=("diy".$type."_".$admin_id);

        if (!extension_loaded('redis')) {
            $model=\app\admin\model\facrm\Setting::detail($cache_key)??new \app\admin\model\facrm\Setting();
            return $model->save(['key'=>$cache_key,'describe'=>'自定义排序','values'=>$params]);

        } else {
            $queue_config=\think\Config::get('queue');
            $redis_cache = \think\Cache::connect([
                'type' => 'redis',
                'password'=>isset($queue_config['password'])?$queue_config['password']:'',
                'host'=>isset($queue_config['host'])?$queue_config['host']:'127.0.0.1',
                'port'=>isset($queue_config['port'])?$queue_config['port']:'6379'
            ]);
            return $redis_cache->tag('diyorder')->set($cache_key, $params);
        }

    }



}
